<script setup lang="ts">
  import type { ActionItem, PopConfirm } from './types'

  import { computed, h, type PropType, reactive, toRaw, type VNode } from 'vue'
  import { Icon } from '../icon'
  import {
    ElButton,
    ElDropdown,
    ElDropdownItem,
    ElDropdownMenu,
    ElMessageBox,
    ElPopconfirm,
    ElSpace
  } from 'element-plus'
  import { useAuth } from '@/composables/useAuth'
  import { isBoolean, isFunction } from 'lodash-es'

  const props = defineProps({
    record: {
      // 行数据
      type: Object,
      default() {
        return {}
      }
    },
    actions: {
      type: Array as PropType<ActionItem[]>,
      default() {
        return []
      }
    },
    dropDownActions: {
      type: Array as PropType<ActionItem[]>,
      default() {
        return []
      }
    },
    divider: {
      type: Boolean,
      default: true
    }
  })
  const emit = defineEmits<{
    (e: 'actionItemClick', record: any): void
  }>()
  const renderIcon = (icon: string | VNode) => {
    if (typeof icon === 'string') {
      return h(Icon, { icon })
    }
    return h(icon)
  }
  const { hasAuth } = useAuth()
  const hasAccessByCodes = (permCodes: string | unknown) => {
    if (permCodes) {
      return hasAuth(permCodes as string)
    }
    return true
  }

  const popconfirmRef = reactive<any>({})
  function isIfShow(action: ActionItem): boolean {
    const ifShow = action.ifShow

    let isIfShow = true

    if (isBoolean(ifShow)) {
      isIfShow = ifShow
    }
    if (ifShow && typeof ifShow === 'function') {
      isIfShow = ifShow(action)
    }
    return isIfShow
  }

  const wrapConfirm = (action: ActionItem) => {
    const newAction = { ...action }

    if (action.confirm) {
      // 重写点击事件
      newAction.onClick = () => {
        emit('actionItemClick', props.record)
        const title = action.confirm.title || '提示'
        const content = action.confirm.content || '确定要执行此操作吗？'
        const options = { ...action.confirm }
        if (!options.type) {
          options.type = 'warning'
        }
        const ok = options.ok
        const cancel = options.cancel
        delete options.title
        delete options.content
        ElMessageBox.confirm(content, title, options)
          .then(() => {
            if (ok && typeof ok === 'function') {
              ok(props.record)
            }
          })
          .catch(() => {
            if (cancel && typeof cancel === 'function') {
              cancel(props.record)
            }
          })
      }
    }
    // 如果存在dialogRef，则直接调用show方法
    if (action.dialogRef) {
      const params =
        (typeof action.dialogParams === 'function'
          ? action.dialogParams(props.record || {})
          : action.dialogParams) || {}
      const dialogRef = action.dialogRef
      newAction.onClick = () => {
        if (isFunction((dialogRef.value || dialogRef).show)) {
          ;(dialogRef.value || dialogRef).show({
            data: {
              ...props.record,
              ...params.data
            },
            ...params
          })
        }
      }
    }
    return newAction
  }

  const getActions = computed(() => {
    return (toRaw(props.actions) || [])
      .filter((action) => {
        return hasAccessByCodes(action.auth) && isIfShow(action)
      })
      .sort((a, b) => (a.sort || 1000) - (b.sort || 1000))
      .map((action) => {
        let processedAction = wrapConfirm(action)
        if (processedAction.dynamicProps && isFunction(processedAction.dynamicProps)) {
          processedAction = {
            ...processedAction,
            ...processedAction.dynamicProps(props.record || {})
          }
        }
        const { popConfirm } = processedAction
        const icon = processedAction.icon ? renderIcon(processedAction.icon) : undefined
        return {
          // getPopupContainer: document.body,
          ...processedAction,
          ...popConfirm,
          icon,
          onConfirm: popConfirm?.confirm,
          onCancel: popConfirm?.cancel,
          enable: !!popConfirm
        }
      })
  })

  const getDropdownList = computed((): any[] => {
    return (toRaw(props.dropDownActions) || [])
      .filter((action) => {
        return hasAccessByCodes(action.auth) && isIfShow(action)
      })
      .sort((a, b) => (a.sort || 1000) - (b.sort || 1000))

      .map((action, index) => {
        let processedAction = wrapConfirm(action)
        if (processedAction.dynamicProps && isFunction(processedAction.dynamicProps)) {
          processedAction = {
            ...processedAction,
            ...processedAction.dynamicProps(props.record || {})
          }
        }
        const { label, popConfirm } = processedAction
        return {
          ...processedAction,
          ...popConfirm,
          onConfirm: popConfirm?.confirm,
          onCancel: popConfirm?.cancel,
          text: label,
          divider: index < props.dropDownActions.length - 1 ? props.divider : false
        }
      })
  })

  const getPopConfirmProps = (attrs: PopConfirm) => {
    const originAttrs: any = { ...attrs }
    delete originAttrs.icon
    if (attrs.confirm && isFunction(attrs.confirm)) {
      const confirm = attrs.confirm
      originAttrs.onConfirm = (e: Event) => {
        confirm(e, props.record)
      }
      delete originAttrs.confirm
    }
    if (attrs.cancel && isFunction(attrs.cancel)) {
      const cancel = attrs.cancel
      originAttrs.onCancel = () => {
        cancel(props.record)
      }
      delete originAttrs.cancel
    }
    return originAttrs
  }

  const getButtonProps = (action: ActionItem): any => {
    const onClick = action.onClick
    const res: any = { ...action }
    if (onClick) {
      res.onClick = (e: Event) => {
        emit('actionItemClick', props.record)
        onClick(e, props.record)
      }
    }
    res.type = action.type || 'primary'
    return res
  }

  const handleCommand = (index: number) => {
    const action = getDropdownList.value[index]
    if (action.onClick && isFunction(action.onClick)) {
      emit('actionItemClick', props.record)
      action.onClick(action, props.record)
    } else {
      const currentPopconfirmRef = popconfirmRef[index.toString()]
      emit('actionItemClick', props.record)
      currentPopconfirmRef?.click(action, props.record)
    }
  }

  const handleRef = (e: any, index: number) => {
    popconfirmRef[index.toString()] = e
  }
</script>

<template>
  <div class="m-table-action">
    <ElSpace :size="2">
      <template v-for="(action, index) in getActions" :key="index">
        <ElPopconfirm v-if="action.popConfirm" v-bind="getPopConfirmProps(action.popConfirm)">
          <template #reference>
            <ElButton v-bind="getButtonProps(action)">
              {{ action.label }}
            </ElButton>
          </template>
        </ElPopconfirm>
        <ElButton v-else v-bind="getButtonProps(action)">
          {{ action.label }}
        </ElButton>
      </template>
    </ElSpace>

    <ElDropdown v-if="getDropdownList.length > 0" trigger="hover" @command="handleCommand">
      <template #default>
        <div>
          <span style="margin-left: 6px">
            <slot name="more">
              <ElButton link type="primary">
                更多
                <template #icon>
                  <Icon class="icon-more" icon="ant-design:bars-outlined" />
                </template>
              </ElButton>
            </slot>
          </span>
          <template v-for="(action, index) in getDropdownList" :key="index">
            <ElPopconfirm v-if="action.popConfirm" v-bind="getPopConfirmProps(action.popConfirm)">
              <template #reference>
                <span :ref="(e) => handleRef(e, index)"></span>
              </template>
            </ElPopconfirm>
          </template>
        </div>
      </template>
      <template #dropdown>
        <ElDropdownMenu>
          <ElDropdownItem v-for="(action, index) in getDropdownList" :key="index" :command="index">
            <Icon v-if="action.icon" :icon="action.icon" />
            <span style="margin-left: 8px">{{ action.label }}</span>
          </ElDropdownItem>
        </ElDropdownMenu>
      </template>
    </ElDropdown>
  </div>
</template>
